package com.example.security1.config;

import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.example.security1.filter.JwtValidateFilter;
import com.example.security1.service.MyUserService;
import com.example.security1.util.Result;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.Principal;
import java.util.*;
import java.util.stream.Collectors;

@Configuration
public class MyWebConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private MyUserService myUserService;

    @Resource
    private JwtValidateFilter jwtValidateFilter;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() //.loginPage("/index.html")// 自定义的登录的页面
                .loginProcessingUrl("/usrlogin") //  提交表单  走的路径的是什么
                .usernameParameter("myname")// index.html  /login
                .passwordParameter("mypwd")
                .successHandler(getSuccess())
                //.defaultSuccessUrl("/success.html") // 默认的成功之后的页面
                .failureHandler(getFail()).permitAll()

                .and().authorizeRequests().antMatchers("/","/index.html","/usrlogin","/zhuanhuan").permitAll() // 、login不需要拦截
                // 有 user的角色  /test    user
                //.and().authorizeRequests().antMatchers("/test").hasRole("user")//hasAuthority("user")
                .and().addFilterBefore(jwtValidateFilter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling().accessDeniedHandler(getAceessDefinedHandle())
                .and().authorizeRequests().anyRequest().authenticated() // 需要认证
                .and().logout().logoutUrl("/logOut").logoutSuccessHandler(getLogOut()).permitAll()
                .and().cors() // 代表可以跨域
                .and().csrf().disable();
    }

    @Bean
    public LogoutSuccessHandler getLogOut() {
        return (request, response, authentication) -> {
            // code msg t
            Result result = Result.success(authentication);
            printJsonData(result,response);
        };
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserService).passwordEncoder(getPasswordEncoder());
    }


    @Bean
    public BCryptPasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }


    @Bean
    public AuthenticationSuccessHandler getSuccess(){
        return (request, response, authentication) -> {
            // 颁发令牌
            Map map = new HashMap();
            // 获取登陆成功的用户的名字
            // 用户的资源的信息
            List<SimpleGrantedAuthority> authorities = (List<SimpleGrantedAuthority>) authentication.getAuthorities();
            List<String> authoryList = authorities.stream().map(simpleGrantedAuthority -> simpleGrantedAuthority.getAuthority()).collect(Collectors.toList());

//            Principal principal = (Principal) authentication.getPrincipal();
//            String name = principal.getName();
            String myname = request.getParameter("myname");
            map.put("username",myname);

            map.put("authorities",authoryList);

            // 有效期 颁发 30 分钟
            Calendar calendar = Calendar.getInstance();
            Date time = calendar.getTime();
            // System.out.println("当前的时间:"+time);

            calendar.add(Calendar.MINUTE,30); // 30   10  表单 15分钟
            Date expiretime = calendar.getTime();

            // 过期时间
            map.put(JWTPayload.EXPIRES_AT,expiretime);
            // 签发的时间
            map.put(JWTPayload.ISSUED_AT,time);
            // 生效的时间
            map.put(JWTPayload.NOT_BEFORE,time);

            String token = JWTUtil.createToken(map, "lfy".getBytes());
            System.out.println(token);


            // 认证成功之后   返回数据
            // 用户的信息
            // code msg t
            Result result = Result.success(token);
            printJsonData(result,response);
        };
    }

    @Bean
    public AuthenticationFailureHandler getFail(){
        return
                (request, response, exception) -> {
                    // 认证成功之后   返回数据
                    // 用户的信息
                    // code msg t
                    Result result = Result.fail(null);
                    printJsonData(result,response);

                };
    }


    @Bean
    public AccessDeniedHandler getAceessDefinedHandle(){
        return (request, response, accessDeniedException) -> {
            Result result = Result.accessDefined(null);
            printJsonData(result,response);
        };
    }



    public void printJsonData(Result result, HttpServletResponse response) throws IOException {
        // 以json的形式 传递除去
        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writeValueAsString(result);
        // 响应到前端
        response.setContentType("application/json;charset=utf8");
        PrintWriter writer = response.getWriter();
        writer.write(s);
        writer.flush();
        writer.close();
    }
}
